#ifndef VETOR_H_
#define VETOR_H_

#include "VetorException.h"
#include "ConstantesGlobais.h"
#include "Mensagens.h"
#include <iostream>

using namespace std;
using namespace entregadepedidos::util::global;

namespace entregadepedidos{

	namespace util{

		namespace entidades{
		
			namespace vetor{

			template <class TIPO> 
			
			class Vetor{
				
			private:

					TIPO *dados; 	// Ponteiro para meu vetor tradicional alocado dinamicamente
					int capacidade; 	// Numero de itens alocado em memoria
					int iterator; 	// Armazena a posicao de inserida do proximo elemento
					
					// Metodo Utilitario
					void geraNovoTamanho(int num_elementos_adicional)throw(VetorException);
				
				public:
					
					Vetor(int tamanhoInicial = 10);
					Vetor(const Vetor &copia);
					virtual ~Vetor();
					
					//Operacoes do vetor
					void insere(TIPO elemento)throw(VetorException); // Excecao vetor cheio
					TIPO getPosicao(int posicao)throw(VetorException); // Excecao fora da faixa de valores validos
					void imprimeValores()throw(VetorException); // Imprime os valores do vetor
					
					// Operadores Logicos!
					bool operator==( Vetor &v_dir );
					bool operator!=( Vetor &v_dir );
					Vetor &operator=(Vetor &v_dir);
					
					//Operadores de Acesso
					TIPO operator[](int posicao);
					
					
				};

				template <class TIPO> 
				Vetor<TIPO>::Vetor(int tamanhoInicial){
									
					dados = new TIPO[tamanhoInicial];
					capacidade = tamanhoInicial;
					iterator = 0;
									
				}
																						
																						
				template <class TIPO>
				Vetor<TIPO>::Vetor(const Vetor &copia){
									
					if(copia.capacidade > 0){
						
						dados = new TIPO[ copia.capacidade ];
											
						for(int i = 0; i < copia.iterator; i++)
							dados[i] = copia.dados[i];
											
					}else{
											
						dados = NULL;
											
					}
																								
					capacidade = copia.capacidade;
					iterator = copia.iterator;
																									
				}
																						
																						
				template <class TIPO> 
				Vetor<TIPO>::~Vetor(){
					delete [] dados;
				}
																						
				template <class TIPO> 
				void Vetor<TIPO>::insere(TIPO elemento)throw(VetorException){
								
					try{
																								
						if (capacidade == iterator){
																										
							//Aumenta o tamanho do vetor, criando um novo e inserindo o valor
							geraNovoTamanho(10);
										
						}
																									
						dados[iterator] = elemento;
						iterator++;	
																									
						}catch(...){
							throw VetorException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETOR_INSERE_ERRO());
						}	
																							
				}
																						
																						
				template <class TIPO> 
				TIPO Vetor<TIPO>::getPosicao(int posicao)throw(VetorException){
																							
					try{
																							
						if (posicao < 0 or posicao > iterator)
											throw VetorException(Mensagens::GET_VETOR_GETPOSICAO_POSICAO_INVALIDA(),Mensagens::GET_VETOR_GETPOSICAO_ERRO());
																							
					}catch(...){
						throw VetorException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETOR_GETPOSICAO_ERRO());
					}
																						
					return dados[posicao];
																						
				}
																						
				template <class TIPO> 
				void Vetor<TIPO>::geraNovoTamanho(int elementosAdicionais)throw(VetorException){
																							
					try{
																							
						int novoTamanho = capacidade + elementosAdicionais;
						TIPO *tmp = new TIPO[novoTamanho];
																							
						for(int i = 0; i < iterator; i++)
							tmp[i] = dados[i];
																							
						TIPO *aux = dados; // variavel auxiliar
						dados = tmp;
						delete [] aux;
						capacidade = novoTamanho;
																								
					}catch(...){
						throw VetorException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETOR_GERANOVOTAMANHO_ERRO());		
					}
									
				}
																			
																			
				/**
				* Mesmo tamanho e todos os valores iguais aos valores de v_dir!!
				*/
				template <class TIPO> 
				bool Vetor<TIPO>::operator==( Vetor &v_dir ){
					if(iterator != v_dir.iterator)
						return false;
					
					for(int i = 0; i < iterator; i++){
						if(dados[i] != v_dir.dados[i])
							return false;
										
					}
																							
					return true;
									
				}
																						
																						
				template <class TIPO> 
				bool Vetor<TIPO>::operator!=( Vetor &v_dir ){
					return ( !(*this == v_dir) );
				}
																						
																						
				template <class TIPO> 
					Vetor<TIPO> &Vetor<TIPO>::operator=(Vetor &v_dir){
																						
						if(dados != NULL)
							delete [] dados;
																										
						capacidade = v_dir.capacidade;
						iterator = v_dir.iterator;
						dados = new TIPO[capacidade];
																							
						for(int i = 0; i < iterator; i++)
							dados[i] = v_dir.dados[i];
																							
						return *this;
																								
				}
																			
																						
				template <class TIPO>
				TIPO Vetor<TIPO>::operator[](int posicao){
					return getPosicao(posicao);	
				}
																						
				template <class TIPO>
				void Vetor<TIPO>::imprimeValores()throw(VetorException){
					try{
					
						for(int i = 0; i < iterator; i++)
							cout << dados[i];
						
					}catch(...){
						throw VetorException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETOR_IMPRIMEVALORES_ERRO());
					}
				}				

			}
			
		}
		
	}
	
}
				
				
#endif /*VETOR_H_*/
